﻿/*************************************************************************************
 *
 * 文 件 名： Worker
 * 描    述： 从模板新增
 * 
 * 版    本： V1.0
 * 创 建 者： YSW
 * 创建时间： 2022-08-24 8:54:29
 * ======================================
 * 历史更新记录
 * 版本：V          修改时间：         修改人：
 * 修改内容：
 * ======================================
*************************************************************************************/

using CommonModel.Model;
using CommonModel.Util;
using Dm;
using GXRTBTC.PublicClassLibrary;
using GXRTBTC.PublicClassLibrary.Model;
using GXRTBTC.PublicClassLibrary.Redis;
using GXRTBTC.PublicClassLibrary.Util;
using IoTSharp.Data.Taos;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NewLife;
using NewLife.Caching;
using NewLife.Data;
using NewLife.Messaging;
using NewLife.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Npgsql;
using RedisHelp;
using StackExchange.Redis;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Net.Http;
using System.Text;
using System.Xml;
using static Dm.net.buffer.ByteArrayBuffer;
using EnumHelper = GXRTBTC.PublicClassLibrary.Util.EnumHelper;

namespace GXRTBTC.DeviceParamSetService
{
    /// <summary>
    /// 后台服务
    /// 使用后台服务，让服务已启动就对Worker进行初始化
    /// </summary>
    public class MyBackgroundService : Microsoft.Extensions.Hosting.BackgroundService
    {
        /// <summary>
        /// 实例Worker这里引用只是为了让其初始化
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="worker"></param>
        public MyBackgroundService(Worker worker) { }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            return Task.CompletedTask;
        }
    }

    /// <summary>
    /// 接收到的数据
    /// </summary>
    public class ReceiveData
    {
        public Func<ReceiveData, Object>? func { get; set; }
        public Object data { get; set; } = "";
        public string ip { get; set; } = "";
        public ushort port { get; set; } = 0;
        public int type { get; set; } = 0;
        public DateTime dateTime { get; set; } = DateTime.Now;
    }

    /// <summary>
    /// 后台服务
    /// </summary>
    public class Worker
    {
        #region 参数
        /// <summary>
        /// 当前节点名称
        /// 组成：节点所在IP+容器ID
        /// </summary>
        //public string nodeName { get; set; } = TransForm.GetContainerAddress() + "_" + Environment.MachineName;
        public string nodeName { get; set; } = TransForm.GetHostIPOrName() + "_" + Environment.MachineName;
        /// <summary>
        /// 日志
        /// </summary>
        public readonly ILogger mLogger;
        /// <summary>
        /// 配置
        /// </summary>
        private readonly IConfiguration mConfiguration;
        /// <summary>
        /// StackExchange.Redis
        /// </summary>
        public RedisHelper redisInit { get; set; }
        private string redisConnString { get; set; } = "";

        /// <summary>
        /// 副本数，默认只有自身
        /// </summary>
        private int nodeNum { get; set; } = 1;
        /// <summary>
        /// 当前副本编号
        /// </summary>
        private int nodeNo { get; set; } = 0;
        /// <summary>
        /// 对象锁
        /// </summary>
        public Object syncLock { get; set; } = new object();
        /// <summary>
        /// 台站编号
        /// </summary>
        private string stationIdGlobal { get; set; } = "";
        /// <summary>
        /// 最小线程池数量
        /// </summary>
        private int minPoolNum { get; set; } = 10;
        /// <summary>
        /// 最大线程池数量
        /// </summary>
        private int maxPoolNum { get; set; } = 500;
        /// <summary>
        /// 数据库连接
        /// </summary>
        private DbConnection dbConnection { get; set; }
        /// <summary>
        /// 总平台达梦数据库
        /// </summary>
        //private DbConnection dmDbConnection { get; set; }
        private bool IsDbConn { get; set; } = false;
        private bool IsDMDbConn { get; set; } = false;
        /// <summary>
        /// 配置集
        /// </summary>
        private Dictionary<string, string> paramInfo { get; set; } = new();
        /// <summary>
        /// 全局变量
        /// 一键读取
        /// </summary>
        private bool realFlag { get; set; } = false;
        /// <summary>
        /// 轮询下发信息
        /// </summary>
        private Dictionary<string, Dictionary<string, string>> cmdSetInfo { get; set; } = new();
        /// <summary>
        /// 最新设置
        /// </summary>
        private Dictionary<string, string> newParamSet { get; set; } = new();
        /// <summary>
        /// http请求池
        /// </summary>
        private HttpClient httpClient { get; set; }
        /// <summary>
        /// 基础数据类型
        /// </summary>
        private Dictionary<string, string> basicType { get; set; } = new();
        /// <summary>
        /// 请求类
        /// </summary>
        private HttpClientUtil httpClientUtil { get; set; }
        private string webUrl { get; set; } = "ws://111.111.8.242:8001/data/1.0/1/0101_svrrcv_1/0";
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="configuration"></param>
        public Worker(ILogger<Worker> logger, IConfiguration configuration)
        {
            this.mLogger = logger;
            this.mConfiguration = configuration;

            //给通用日志赋值
            CommonUtil.mLogger = logger;

            //初始化
            Init();
            mLogger.LogInformation("项目已启动");
        }

        #region 初始化
        public void Init()
        {
            //线程池配置
            ThreadPool.SetMinThreads(minPoolNum, minPoolNum);
            ThreadPool.SetMaxThreads(maxPoolNum, maxPoolNum);

            try
            {
                //redis初始化
#if DEBUG
                redisConnString = RsaEncrypt.DecryptFree(mConfiguration["RedisConnStringDebug"]);
#else
                redisConnString = RsaEncrypt.DecryptFree(mConfiguration["RedisConnString"]);
#endif
                redisInit = new RedisHelper(redisConnString, mLogger);
            }
            catch { }

            //基础数据类型，用于判断是否直接保存
            //basicType.TryAdd(typeof(sbyte).Name, "");
            //basicType.TryAdd(typeof(byte).Name, "");
            basicType.TryAdd(typeof(short).Name, "");
            basicType.TryAdd(typeof(ushort).Name, "");
            basicType.TryAdd(typeof(int).Name, "");
            basicType.TryAdd(typeof(uint).Name, "");
            basicType.TryAdd(typeof(long).Name, "");
            basicType.TryAdd(typeof(ulong).Name, "");
            basicType.TryAdd(typeof(float).Name, "");
            basicType.TryAdd(typeof(double).Name, "");
            basicType.TryAdd(typeof(char).Name, "");
            basicType.TryAdd(typeof(string).Name, "");
            basicType.TryAdd(typeof(bool).Name, "");

            httpClient = new HttpClient();
            httpClientUtil = new HttpClientUtil(mLogger);

            dbConnection = InitDb();
            //dmDbConnection = GetDMDb();
            //new Thread(InitDmDb).Start();
            InitCacheInfo();
            InitThread();
        }

        /// <summary>
        /// 启动线程
        /// </summary>
        private void InitThread()
        {
            new Thread(TimerInit).Start();
            new Thread(Polling).Start();
            new Thread(TimerTask).Start();
        }

        //private void InitDmDb()
        //{
        //    dmDbConnection = GetDMDb();
        //}

        /// <summary>
        /// 初始化信息
        /// </summary>
        private void TimerInit()
        {
            Thread.Sleep(60 * 1000);
            while (true)
            {
                //redis缓存信息初始化
                InitCacheInfo();
                CheckDbState();
                //CheckDmDbState();
                Thread.Sleep(60 * 1000);
            }
        }

        /// <summary>
        /// redis缓存信息初始化
        /// </summary>
        private void InitCacheInfo()
        {
            try
            {
                paramInfo = redisInit.HashGetAllDict<string>("paramInfo");
                webUrl = paramInfo.GetValueOrDefault("WebReceiveDataUrl", "ws://111.111.8.242:8001/data/1.0/1/0101_svrrcv_1/0");

                //改为直接从数据库拿
                //Dictionary<string, Dictionary<string, string>> tmpCmdSetInfo = redisInit.HashGetAllDict<Dictionary<string, string>>("cmdSetInfo");
                Dictionary<string, Dictionary<string, string>> tmpCmdSetInfo = DbUtil.GetCmdSetInfo(dbConnection);
                cmdSetInfo = (tmpCmdSetInfo != null && tmpCmdSetInfo.Count > 0) ? tmpCmdSetInfo : cmdSetInfo;

                Dictionary<string, string> tmpNewParamSet = DbUtil.GetLatestParamSetData(dbConnection);
                newParamSet = (tmpNewParamSet != null && tmpNewParamSet.Count > 0) ? tmpNewParamSet : newParamSet;

                Dictionary<string, Dictionary<string, string>> stationsInfo = redisInit.StringGet<Dictionary<string, Dictionary<string, string>>>("stations");
                //全局台站编号
                stationIdGlobal = (stationsInfo.Count > 0 ? stationsInfo.First().Key : stationIdGlobal);
            }
            catch (Exception e)
            {
                mLogger.LogInformation("更新获取台站信息缓存失败，" + e);
            }
        }

        /// <summary>
        /// 数据库初始化
        /// </summary>
        private DbConnection InitDb()
        {
            DbConnection? dbconn = null;
            try
            {
                //添加解密
                dbconn = new NpgsqlConnection(RsaEncrypt.DecryptFree(mConfiguration["PgSQLConnString"]));
                dbconn.Open();
                IsDbConn = true;
                mLogger.LogInformation("pgSQL数据库连接成功！");
            }
            catch (Exception e)
            {
                IsDbConn = false;
                mLogger.LogError("pgSQL数据库连接失败！" + e.Message);
            }

            return dbconn;
        }

        /// <summary>
        /// 检查数据库连接
        /// </summary>
        /// <param name="dbConnection"></param>
        private void CheckDbState()
        {
            try
            {
                DbUtil.ExecReader(dbConnection, "select 1 col1", false);
                if (dbConnection.State != ConnectionState.Open)
                {
                    dbConnection.Close();
                    dbConnection.Open();
                }
                IsDbConn = true;
            }
            catch (Exception e)
            {
                IsDbConn = false;
                mLogger.LogError("数据库连接失败！" + e.Message);
            }
        }

        /// <summary>
        /// 达梦数据库初始化
        /// </summary>
        /// <returns></returns>
        //private DbConnection GetDMDb() 
        //{
        //    DbConnection? dbconn = null;
        //    try
        //    {
        //        //添加解密
        //        string dmConnString = RsaEncrypt.DecryptFree(mConfiguration["DMConnString"]);
        //        dbconn = new DmConnection(dmConnString);
        //        dbconn.Open();
        //        IsDMDbConn = true;
        //        mLogger.LogInformation("达梦数据库连接成功！");
        //    }
        //    catch (Exception e)
        //    {
        //        IsDMDbConn = false;
        //        mLogger.LogError("达梦数据库连接失败！" + e.Message);
        //    }

        //    return dbconn;
        //}

        /// <summary>
        /// 检查数据库连接
        /// </summary>
        /// <param name="dbConnection"></param>
        //private void CheckDmDbState()
        //{
        //    try
        //    {
        //        DbUtil.ExecReader(dmDbConnection, "select 1 col1", false);
        //        if (dmDbConnection.State != ConnectionState.Open)
        //        {
        //            dmDbConnection.Close();
        //            dmDbConnection.Open();
        //        }
        //        IsDMDbConn = true;
        //    }
        //    catch (Exception e)
        //    {
        //        IsDMDbConn = false;
        //        mLogger.LogError("达梦数据库连接失败！" + e.Message);
        //    }
        //}

        /// <summary>
        /// 设置访问统计
        /// </summary>
        /// <param name="httpContext"></param>
        public void SetStatistics(HttpContext HttpContext)
        {

        }
        #endregion

        #region 接口 
        /// <summary>
        /// 默认配置变更
        /// </summary>
        /// <param name="id"></param>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public CommonRes SetDft(string id, HttpContext httpContext)
        {
            CommonRes commonRes = new CommonRes();

            try
            {
                if (IsDbConn)
                {
                    if (TransForm.IsInt(id))
                    {
                        string sql = "select cmd_id from param_data_his where id={0}";
                        int cmdId = DbUtil.GetExecInt(dbConnection, sql, int.Parse(id));
                        if (cmdId > 0)
                        {
                            sql = "update param_data_his set mark_flag = (case id when {0} then 1 else 0 end) where cmd_id={1}";
                            if (!DbUtil.ExecSql(dbConnection, sql, int.Parse(id), cmdId))
                            {
                                commonRes.Code = WebApiStatusCode.code_500;
                                commonRes.Message = "设置错误，步骤1";
                            }
                            else
                            {
                                if (!SetDefaultSet(int.Parse(id)))
                                {
                                    commonRes.Code = WebApiStatusCode.code_500;
                                    commonRes.Message = "设置错误，步骤2";
                                }
                            }
                        }
                        else
                        {
                            commonRes.Code = WebApiStatusCode.code_500;
                            commonRes.Message = "未找到id=" + id + "的条目";
                        }
                    }
                    else
                    {
                        {
                            commonRes.Code = WebApiStatusCode.code_500;
                            commonRes.Message = "id参数异常";
                        }
                    }
                }
                else
                {
                    commonRes.Code = WebApiStatusCode.code_500;
                    commonRes.Message = "数据库无法连接";
                }
            }
            catch (Exception e)
            {
                commonRes.Code = WebApiStatusCode.code_5501;
                commonRes.Message = e.Message;
            }

            return commonRes;
        }

        /// <summary>
        /// 获取设置预览
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public CommonDataRes ReadSetView(HttpContext httpContext)
        {
            CommonDataRes commonDataRes = new CommonDataRes();

            try
            {
                if (IsDbConn)
                {
                    string sql = "select a.id, a.set_id, a.dev_id, b.device_type, NULLIF(b.device_type, b.device_name) device_name, b.position_id, c.set_name, case a.is_used when true then '启用' else '未启用' end is_used, a.send_gap, d.get_time, d.change_text  " +
                        "from cmd_set a left join (select e.cmd_id, e.change_text, e.get_time from param_data_his e where id in(select max(f.id) from param_data_his f group by f.cmd_id)) d on a.id = d.cmd_id,  " +
                        "device_info b, dev_param_set c where a.dev_id = b.id and a.set_id = c.id order by b.device_type, b.position_id, c.set_name";
                    commonDataRes.Data = DbUtil.ExecReader(dbConnection, sql);
                }
                else
                {
                    commonDataRes.Code = WebApiStatusCode.code_500;
                    commonDataRes.Message = "数据库无法连接";
                }
            }
            catch (Exception e)
            {
                commonDataRes.Code = WebApiStatusCode.code_5501;
                commonDataRes.Message = e.Message;
            }

            return commonDataRes;
        }

        /// <summary>
        /// 获取变更历史
        /// </summary>
        /// <param name="devId"></param>
        /// <param name="setId"></param>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public CommonDataRes GetChangeHis(int cmdId, HttpContext httpContext, int pageIndex = 1, int pageSize = 20)
        {
            CommonDataRes commonDataRes = new CommonDataRes();

            try
            {
                if (IsDbConn)
                {
                    string where = " and cmd_id=" + cmdId;
                    string sql = "select a.id, a.cmd_id, b.dev_id, NULLIF(d.device_type, d.device_name) device_name, c.set_name, a.set_text, a.change_text, case a.mark_flag when 1 then '默认' else '' end mark_flag, a.get_time " +
                        "from param_data_his a, cmd_set b, dev_param_set c, device_info d where a.cmd_id=b.id and b.set_id = c.id and b.dev_id = d.id " + where + " order by id desc";
                    //commonDataRes.Data = DbUtil.ExecReader(dbConnection, sql);
                    PageResult ps = PageUtil.GetPageDatas(dbConnection, sql, new Page() { pageIndex = pageIndex, pageSize = pageSize, paging = true });
                    if (ps != null && ps.result)
                    {
                        commonDataRes.Data = ps;
                    }
                    else
                    {
                        commonDataRes.Code = WebApiStatusCode.code_500;
                        commonDataRes.Message = ps.message;
                    }
                }
                else
                {
                    commonDataRes.Code = WebApiStatusCode.code_500;
                    commonDataRes.Message = "数据库无法连接";
                }
            }
            catch (Exception e)
            {
                commonDataRes.Code = WebApiStatusCode.code_5501;
                commonDataRes.Message = e.Message;
            }

            return commonDataRes;
        }

        /// <summary>
        /// 一键读取
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public CommonRes ReadAll(HttpContext httpContext)
        {
            CommonRes commonRes = new CommonRes();

            try
            {
                //打全局读取标志
                realFlag = true;
            }
            catch (Exception e)
            {
                commonRes.Code = WebApiStatusCode.code_5501;
                commonRes.Message = e.Message;
            }

            return commonRes;
        }

        /// <summary>
        /// 一键读取
        /// 给主控用，读取丢失后可以从这里读取
        /// </summary>
        /// <param name="positionId"></param>
        /// <returns></returns>
        public CommonDataRes ReadSets(string positionId, HttpContext httpContext)
        {
            CommonDataRes commonDataRes = new CommonDataRes();

            try
            {
                if (IsDbConn)
                {
                    if (!string.IsNullOrEmpty(positionId))
                    {
                        string sql = "select c.set_code, c.set_name, d.position_id, d.device_type ,a.set_text " +
                            "from station_param_data_his a, cmd_set b, dev_param_set c, device_info d " +
                            "where a.cmd_id=b.id and b.set_id = c.id and b.dev_id = d.id and d.position_id='" + positionId + "' order by c.id";
                        List<Dictionary<string, string>> lsDetail = DbUtil.ExecReader(dbConnection, sql);
                        Dictionary<string, Dictionary<string, string>> devSets = new();
                        if (lsDetail != null)
                        {
                            foreach (var detail in lsDetail)
                            {
                                string setCode = detail["set_code"];
                                if (!devSets.ContainsKey(setCode))
                                {
                                    devSets.TryAdd(setCode, detail);
                                }
                            }
                        }
                        commonDataRes.Data = devSets;
                    }
                    else
                    {
                        commonDataRes.Code = WebApiStatusCode.code_400;
                        commonDataRes.Message = "参数错误";
                    }
                }
                else
                {
                    commonDataRes.Code = WebApiStatusCode.code_500;
                    commonDataRes.Message = "数据库无法连接";
                }
            }
            catch (Exception e)
            {
                commonDataRes.Code = WebApiStatusCode.code_5501;
                commonDataRes.Message = e.Message;
            }

            return commonDataRes;
        }

        /// <summary>
        /// 查看默认
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public CommonDataRes ReadDft(HttpContext httpContext)
        {
            CommonDataRes commonDataRes = new CommonDataRes();

            try
            {
                if (IsDbConn)
                {
                    string sql = "select a.id, a.cmd_id, b.dev_id, NULLIF(d.device_type, d.device_name) device_name, d.position_id, d.device_type,c.set_name, a.set_text, a.get_time  " +
                    "from station_param_data_his a, cmd_set b, dev_param_set c, device_info d  " +
                    "where a.cmd_id=b.id and b.set_id = c.id and b.dev_id = d.id  order by id desc";

                    commonDataRes.Data = DbUtil.ExecReader(dbConnection, sql);
                }
                else
                {
                    commonDataRes.Code = WebApiStatusCode.code_500;
                    commonDataRes.Message = "数据库无法连接";
                }
            }
            catch (Exception e)
            {
                commonDataRes.Code = WebApiStatusCode.code_5501;
                commonDataRes.Message = e.Message;
            }

            return commonDataRes;
        }

        /// <summary>
        /// 设置比对
        /// 总平台发起
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public CommonRes CompareSet(HttpContext httpContext)
        {
            CommonDataRes commonDataRes = new CommonDataRes();

            try
            {
                if (IsDbConn)
                {
                    //这里也处理数据
                    var len = Convert.ToInt32(httpContext.Request.ContentLength);
                    byte[] buffer = new byte[len];
                    string data = "";
                    //循坏才能读取所有数据
                    var stream = httpContext.Request.BodyReader.AsStream();
                    int bytesRead;
                    while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        data += Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    }

                    List<Dictionary<string, string>> dftSetDetails = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(data);
                    List<Dictionary<string, string>> rsDetail = new List<Dictionary<string, string>>();
                    if (dftSetDetails != null && dftSetDetails.Count > 0)
                    {
                        int idx = 1;
                        foreach (var dftSet in dftSetDetails)
                        {
                            //string id = dftSet["id"];
                            string positionId = dftSet["position_id"];
                            string cmdId = dftSet["cmd_id"];
                            string setText = dftSet["set_text"];

                            Dictionary<string, string> rsDict = new Dictionary<string, string>() { { "id", idx.ToString() }, { "is_same", "true" }, { "message", "" } };

                            string sql = string.Format("select set_text from station_param_data_his where station_id='{0}' and position_id='{1}' and cmd_id={2}", stationIdGlobal, positionId, cmdId);
                            string tmpSetText = DbUtil.GetExecValue(dbConnection, sql);

                            if (string.IsNullOrEmpty(tmpSetText))
                            {
                                //台站端缺少数据
                                rsDict["is_same"] = false.ToString();
                                rsDict["message"] = "台站缺少配置";
                            }
                            else
                            {
                                //台站端缺少数据
                                rsDict["is_same"] = setText.Equals(tmpSetText).ToString();
                            }
                            rsDetail.Add(rsDict);
                            idx++;
                        }

                        commonDataRes.Message = "";
                        commonDataRes.Data = rsDetail;
                    }
                    else
                    {
                        commonDataRes.Code = WebApiStatusCode.code_501;
                        commonDataRes.Message = "没有需要检查的配置";
                    }
                }
                else
                {
                    commonDataRes.Code = WebApiStatusCode.code_501;
                    commonDataRes.Message = "数据库连接失败，无法检查";
                }
            }
            catch (Exception e)
            {
                commonDataRes.Code = WebApiStatusCode.code_5501;
                commonDataRes.Message = e.Message;
            }

            return commonDataRes;
        }

        /// <summary>
        /// 从台站同步
        /// 总平台发起
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public CommonDataRes SyncFrom(HttpContext httpContext)
        {
            CommonDataRes commonDataRes = new CommonDataRes();

            try
            {
                if (IsDbConn)
                {
                    //返回所有设置给到总平台
                    string sql = "select a.id, a.cmd_id, '" + stationIdGlobal + "' station_id, d.position_id, d.serial_no, c.set_name, c.set_code, a.set_text " +
                        "from station_param_data_his a, cmd_set b, dev_param_set c, device_info d " +
                        "where a.cmd_id=b.id and b.set_id = c.id and b.dev_id = d.id  order by id desc";
                    List<Dictionary<string, string>> dftSetDetails = DbUtil.ExecReader(dbConnection, sql);
                    commonDataRes.Data = dftSetDetails;
                }
                else
                {
                    commonDataRes.Code = WebApiStatusCode.code_501;
                    commonDataRes.Message = "数据库连接失败，无法同步";
                }
            }
            catch (Exception e)
            {
                commonDataRes.Code = WebApiStatusCode.code_5501;
                commonDataRes.Message = e.Message;
            }

            return commonDataRes;
        }

        /// <summary>
        /// 同步至台站
        /// 总平台发起
        /// </summary>
        /// <param name="data"></param>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public CommonDataRes SyncTo(string data, HttpContext httpContext)
        {
            CommonDataRes commonDataRes = new CommonDataRes();

            try
            {
                if (IsDbConn)
                {
                    List<Dictionary<string, string>> dftSetDetails = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(data);
                    if (dftSetDetails != null && dftSetDetails.Count > 0)
                    {
                        List<Dictionary<string, string>> rsDetail = new List<Dictionary<string, string>>();
                        int idx = 1;
                        string msg = "同步条数：" + dftSetDetails.Count;
                        foreach (var dftSet in dftSetDetails)
                        {
                            //string id = dftSet["id"];
                            string positionId = dftSet["position_id"];
                            string cmdId = dftSet["cmd_id"];
                            string serialNo = dftSet["serial_no"];
                            string setName = dftSet["set_name"];
                            string setCode = dftSet["set_code"];
                            string setText = dftSet["set_text"];
                            Dictionary<string, string> rsDict = new Dictionary<string, string>() { { "id", idx.ToString() }, { "sync", "true" }, { "message", "" } };

                            string sql = string.Format("select set_text from station_param_data_his where position_id='{1}' and cmd_id={2}", positionId, cmdId);
                            string tmpSetText = DbUtil.GetExecValue(dbConnection, sql);
                            if (string.IsNullOrEmpty(tmpSetText))
                            {
                                sql = string.Format("insert into station_param_data_his(cmd_id, station_id, position_id, serial_no, set_name, set_code, set_text, memo, is_same) " +
                                    "values({0},'{1}','{2}','{3}','{4}','{5}','{6}', '{7}')", cmdId, stationIdGlobal, positionId, serialNo, setName, setCode, setText, "从台站同步", "true");
                                if (!DbUtil.ExecSql(dbConnection, sql))
                                {
                                    msg += string.Format("，position_id={0}&setName={1} 新增同步失败", positionId, setName);
                                    rsDict["message"] = string.Format("position_id={0}&setName={1} 新增同步失败", positionId, setName);
                                }
                                else
                                {
                                    msg += string.Format("，position_id={0}&setName={1} 新增同步成功", positionId, setName);
                                    rsDict["message"] = string.Format("position_id={0}&setName={1} 新增同步成功", positionId, setName);
                                }

                                //历史表去掉默认
                                sql = "update param_data_his set mark_flag = 0 where cmd_id=" + cmdId;
                                DbUtil.ExecSql(dbConnection, sql);
                            }
                            else if (!tmpSetText.Equals(setText))
                            {
                                sql = string.Format("update station_param_data_his set set_name='{0}', get_time=now(), set_text='{1}', memo='从总平台更新', is_same = true where station_id='{2}' and position_id='{3}' and cmd_id={4}",
                                    setName, setText, stationIdGlobal, positionId, cmdId);
                                if (!DbUtil.ExecSql(dbConnection, sql))
                                {
                                    msg += string.Format("，position_id={0}&setName={1} 更新同步失败", positionId, setName);
                                    rsDict["message"] = string.Format("position_id={0}&setName={1} 更新同步失败", positionId, setName);
                                }
                                else
                                {
                                    msg += string.Format("，position_id={0}&setName={1} 更新同步成功", positionId, setName);
                                    rsDict["message"] = string.Format("position_id={0}&setName={1} 更新同步成功", positionId, setName);
                                }

                                //历史表去掉默认
                                sql = "update param_data_his set mark_flag = 0 where cmd_id=" + cmdId + " and set_text != '" + setText + "'";
                                DbUtil.ExecSql(dbConnection, sql);
                            }
                            else
                            {
                                msg += string.Format("，position_id={0}&setName={1} 不需要更新", positionId, setName);
                                rsDict["message"] = string.Format("position_id={0}&setName={1} 不需要更新", positionId, setName);
                            }

                            rsDetail.Add(rsDict);
                            idx++;
                        }

                        commonDataRes.Message = msg;
                        commonDataRes.Data = rsDetail;
                    }
                    else
                    {
                        commonDataRes.Code = WebApiStatusCode.code_501;
                        commonDataRes.Message = "没有需要同步的配置";
                    }
                }
                else
                {
                    commonDataRes.Code = WebApiStatusCode.code_501;
                    commonDataRes.Message = "数据库连接失败，无法同步";
                }
            }
            catch (Exception e)
            {
                commonDataRes.Code = WebApiStatusCode.code_5501;
                commonDataRes.Message = e.Message;
            }

            return commonDataRes;
        }

        /// <summary>
        /// 一键设置
        /// 给总平台用
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public async Task<CommonRes> ParamSetToDev(HttpContext httpContext)
        {
            CommonDataRes commonDataRes = new CommonDataRes();
            try
            {
                if (IsDbConn)
                {

                    //这里也处理数据
                    var len = Convert.ToInt32(httpContext.Request.ContentLength);
                    byte[] buffer = new byte[len];
                    string data = "";
                    //循坏才能读取所有数据
                    var stream = httpContext.Request.BodyReader.AsStream();
                    int bytesRead;
                    while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        data += Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    }

                    commonDataRes = SyncTo(data, httpContext);
                    if (commonDataRes.Code.Equals(WebApiStatusCode.code_200))
                    {
                        List<Dictionary<string, string>> dftSetDetails = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(data);
                        List<Dictionary<string, string>> rsDetail = new List<Dictionary<string, string>>();
                        if (dftSetDetails != null && dftSetDetails.Count > 0)
                        {
                            int idx = 1;
                            foreach (var dftSet in dftSetDetails)
                            {
                                //string id = dftSet["id"];
                                string positionId = dftSet["position_id"];
                                string cmdId = dftSet["cmd_id"];
                                string serialNo = dftSet["serial_no"];
                                string setName = dftSet["set_name"];
                                string setCode = dftSet["set_code"];
                                string setText = dftSet["set_text"];
                                Dictionary<string, string> rsDict = new Dictionary<string, string>() { { "id", idx.ToString() }, { "status", "true" }, { "message", "" } };

                                string sql = string.Format("select set_text from station_param_data_his where position_id='{1}' and cmd_id={2}", positionId, cmdId);
                                string tmpId = DbUtil.GetExecValue(dbConnection, sql);
                                CommonRes tmpCommonRes = ParamSetTo(tmpId, httpContext).Result;
                                rsDict["status"] = tmpCommonRes.Code.Equals(WebApiStatusCode.code_200).ToString();
                                rsDict["message"] = tmpCommonRes.Message;

                                rsDetail.Add(rsDict);
                                idx++;
                            }

                            commonDataRes.Message = "";
                            commonDataRes.Data = rsDetail;
                        }
                        else
                        {
                            commonDataRes.Code = WebApiStatusCode.code_501;
                            commonDataRes.Message = "没有需要同步的配置";
                        }
                    }
                }
            }
            catch (Exception e)
            {
                commonDataRes.Code = WebApiStatusCode.code_5501;
                commonDataRes.Message = e.Message;
            }

            return commonDataRes;
        }

        /// <summary>
        /// 一键设置
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public async Task<CommonRes> ParamSetTo(string ids, HttpContext httpContext)
        {
            CommonRes commonRes = new CommonRes();

            try
            {
                if (!IsDbConn)
                {
                    commonRes.Code = WebApiStatusCode.code_500;
                    commonRes.Message = "数据库无法连接";
                    return commonRes;
                }

                //暂时不允许这样操作
                if (string.IsNullOrEmpty(ids))
                {
                    commonRes.Code = WebApiStatusCode.code_400;
                    commonRes.Message = "ids参数不能为空";
                    return commonRes;
                }

                //无数据时，是默认全部下发，这是个危险的操作
                string where = string.IsNullOrEmpty(ids) ? "" : (" and s.id in('" + ids.Replace(",", "','") + "')");
                //从station_param_data_his读取默认设置
                List<Dictionary<string, string>> dftSetDetails = DbUtil.ExecReader(dbConnection, string.Format("select s.*, a.dev_id, a.set_id from station_param_data_his s, cmd_set a where a.id = s.cmd_id and s.station_id = '{0}' {1}", stationIdGlobal, where));

                if (dftSetDetails != null && dftSetDetails.Count > 0)
                {
                    string msg = "配置数量：" + dftSetDetails.Count;
                    int idx = 1;
                    foreach (var setData in dftSetDetails)
                    {
                        string setId = setData["set_id"];
                        string devId = setData["dev_id"];
                        string key = devId + "#" + setId;
                        string paramData = setData["set_text"];
                        msg += "；结果【" + idx + "】：";

                        if (cmdSetInfo.ContainsKey(key))
                        {
                            Dictionary<string, string> setInfo = cmdSetInfo[key];
                            string setType = cmdSetInfo[key]["set_type"].ToUpper();
                            string positionId = cmdSetInfo[key]["position_id"];
                            string setName = cmdSetInfo[key]["set_name"];

                            bool positionOffLine = GetPositionOffLine(positionId);
                            if (!positionOffLine)
                            {
                                //构建请求，必须包含工位号position_id和操作类型operate_type
                                Dictionary<string, string> Data = new Dictionary<string, string>() { { "position_id", positionId }, { "operate_type", setType } };
                                WebApiDataRes webApiData = (WebApiDataRes)httpClientUtil.SendTo(JsonConvert.SerializeObject(Data), "getdata", webUrl).Result;
                                if (!webApiData.Code.Equals(WebApiStatusCode.code_200))
                                {
                                    string result = JsonConvert.SerializeObject(webApiData.Data);
                                    msg += "，设备【dev_id=" + devId + "】-设置【set_id=" + setId + "】设置结果：" + result;
                                }
                                else
                                {
                                    mLogger.LogError($"设置{setName}到{positionId}失败！");
                                    msg += $"设置{setName}到{positionId}失败！";
                                }
                            }
                            else
                            {
                                msg += "，设备【dev_id=" + devId + "】-设置【set_id=" + setId + "】" + positionId + "设备离线，无法设置";
                            }
                        }
                        else
                        {
                            msg += "，设备【dev_id=" + devId + "】-设置【set_id=" + setId + "】未匹配到下发配置";
                        }

                        idx++;
                    }

                    commonRes.Message = msg;
                }
                else
                {
                    commonRes.Code = WebApiStatusCode.code_500;
                    commonRes.Message = "无数据";
                }
            }
            catch (Exception e)
            {
                commonRes.Code = WebApiStatusCode.code_5501;
                commonRes.Message = e.Message;
            }

            return commonRes;
        }
        #endregion

        #region 轮询
        /// <summary>
        /// 轮询设备配置项，并进行比对
        /// </summary>
        private async void Polling()
        {
            Stopwatch sw;
            //判断间隔
            int interval = 1000;
            Thread.Sleep(interval);
            Dictionary<string, DateTime> sendTime = new();
            while (true) 
            {
                sw = Stopwatch.StartNew();
                //全局读取标志
                bool tmpRead = realFlag;
                realFlag = false;
                try
                {
                    foreach (string key in cmdSetInfo.Keys)
                    {
                        if (!sendTime.ContainsKey(key))
                        {
                            sendTime.TryAdd(key, default(DateTime));
                        }
                        DateTime dtNow = DateTime.Now;

                        string cmdId = cmdSetInfo[key]["id"];
                        string setCode = cmdSetInfo[key]["set_code"];

                        string setId = cmdSetInfo[key]["set_id"];
                        string devType = cmdSetInfo[key]["device_type"];
                        string positionId = cmdSetInfo[key]["position_id"];
                        string getType = cmdSetInfo[key]["get_type"];
                        string setName = cmdSetInfo[key]["set_name"];

                        int sendGap = int.Parse(cmdSetInfo[key]["send_gap"]);

                        //数据来自旧主控时，不进行抓取
                        if (GetPositionFromUdp(positionId))
                        {
                            continue;
                        }

                        bool positionOffLine = GetPositionOffLine(positionId);
                        //定时时间到或者一键读取
                        if (!positionOffLine && (sendTime[key] == default(DateTime) || (dtNow - sendTime[key]).TotalSeconds >= sendGap || tmpRead))
                        {
                            sendTime[key] = dtNow;

                            //构建请求，必须包含工位号position_id和操作类型operate_type
                            Dictionary<string, string> Data = new Dictionary<string, string>() { { "position_id", positionId }, { "operate_type", getType } };
                            WebApiDataRes webApiData = (WebApiDataRes)httpClientUtil.SendTo(JsonConvert.SerializeObject(Data), "getdata", webUrl).Result;
                            if (!webApiData.Code.Equals(WebApiStatusCode.code_200))
                            {
                                string result = JsonConvert.SerializeObject(webApiData.Data);

                                //判断是否有变化
                                if (newParamSet.ContainsKey(cmdId))
                                {
                                    if (!newParamSet[cmdId].Equals(result))
                                    {
                                        RecordToChangeHis(cmdId, result, newParamSet[cmdId]);
                                        newParamSet[cmdId] = result;
                                    }
                                }
                                else
                                {
                                    RecordToChangeHis(cmdId, result);
                                    //完全没有，则新增
                                    newParamSet.TryAdd(cmdId, result);
                                }
                            }
                            else
                            {
                                mLogger.LogError($"从{positionId}获取{setName}失败！");
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    mLogger.LogError("轮询异常，" + e);
                }
                finally
                {
                    int gap = (int)sw.ElapsedMilliseconds + 10;
                    Thread.Sleep(gap >= interval ? 1 : (interval - gap));
                }
            }
        }

        /// <summary>
        /// 获取工位号在线状态
        /// </summary>
        /// <param name="positionId"></param>
        /// <returns></returns>
        private bool GetPositionOffLine(string positionId)
        {
            //是否离线
            //string val = mRedisCache.GetString("online_" + positionId);
            string val = redisInit.StringGet("online_" + positionId);
            //获取不到值也判断为离线
            if (val != null && "0".Equals(val))
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 获取工位号是否来自udp，即旧主控的UDP
        /// </summary>
        /// <param name="positionId"></param>
        /// <returns></returns>
        private bool GetPositionFromUdp(string positionId)
        {
            string jsonFlag = redisInit.HashGet("DATA_" + positionId, "json_flag");
            if (string.IsNullOrEmpty(jsonFlag) || "0".Equals(jsonFlag))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 记录变更到数据库
        /// </summary>
        /// <param name="cmdId"></param>
        /// <param name="setText"></param>
        /// <param name="setTextPre"></param>
        public void RecordToChangeHis(string cmdId, string setText, string setTextPre = "")
        {
            bool change = GetChangeText(setText, setTextPre, out string changeText, out string memo);
            //这里再判断一次，因为检查时要去掉对日期时间的判断
            if (change)
            {
                string sql = string.Format("insert into param_data_his(cmd_id, set_text, change_text, memo, mark_flag) values({0},'{1}','{2}','{3}',{4})", cmdId, setText, changeText, memo, string.IsNullOrEmpty(setTextPre) ? 1 : 0);
                DbUtil.ExecSql(dbConnection, sql);

                if (string.IsNullOrEmpty(setTextPre))
                {
                    SetDefaultSetFirst();
                }
            }
        }

        /// <summary>
        /// 首次返回，设置默认设置
        /// </summary>
        private void SetDefaultSetFirst()
        {
            string sql = "insert into station_param_data_his(station_id, position_id, serial_no, set_name, set_code, set_text, get_time, memo, cmd_id) " +
                "select '" + stationIdGlobal + "', d.position_id, d.serial_no, e.set_name, e.set_code, a.set_text, now(), '自动初始化', a.cmd_id " +
                "from param_data_his a, cmd_set c, device_info d, dev_param_set e " +
                "where a.cmd_id = c.id and c.dev_id = d.id and c.set_id = e.id " +
                "and not exists(select from station_param_data_his b where a.cmd_id = b.cmd_id)";
            DbUtil.ExecSql(dbConnection, sql);
        }

        /// <summary>
        /// 设置一条默认
        /// </summary>
        /// <param name="cmdId"></param>
        private bool SetDefaultSet(int id)
        {
            SetDefaultSetFirst();

            string sql = "update station_param_data_his s set set_text = a.set_text, get_time = now() " +
                "from param_data_his a where s.cmd_id = a.cmd_id and a.id = " + id;
            return DbUtil.ExecSql(dbConnection, sql);
        }

        /// <summary>
        /// 判断获取变动信息
        /// </summary>
        /// <param name="setText"></param>
        /// <param name="setTextPre"></param>
        /// <param name="changeText"></param>
        /// <param name="memo"></param>
        /// <returns></returns>
        private bool GetChangeText(string setText, string setTextPre, out string changeText, out string memo)
        {
            bool change = false;
            Dictionary<string, Dictionary<string, string>> changeDict = new() { { "add", new() }, { "upd", new() }, { "del", new() } };
            memo = string.IsNullOrEmpty(setTextPre) ? "首次获取" : "有变化";
            try
            {
                if (!string.IsNullOrEmpty(setTextPre))
                {
                    //Dictionary<string, string> dictParam = GetDataFromJson(new(), JsonConvert.DeserializeObject<Dictionary<string, Object>>(setText));
                    //Dictionary<string, string> dictParamPre = GetDataFromJson(new(), JsonConvert.DeserializeObject<Dictionary<string, Object>>(setTextPre));
                    Dictionary<string, string> dictParam = GetDataFromJson(new(), JsonConvert.DeserializeObject<Dictionary<string, Object>>(setText)).Where(d => !d.Key.ToUpper().Contains("DATE") && !d.Key.ToUpper().Contains("TIME")).ToDictionary(d => d.Key, d => d.Value);
                    Dictionary<string, string> dictParamPre = GetDataFromJson(new(), JsonConvert.DeserializeObject<Dictionary<string, Object>>(setTextPre)).Where(d => !d.Key.ToUpper().Contains("DATE") && !d.Key.ToUpper().Contains("TIME")).ToDictionary(d => d.Key, d => d.Value);

                    foreach (string paramKey in dictParam.Keys)
                    {
                        if (!dictParamPre.ContainsKey(paramKey))
                        {
                            changeDict["add"].Add(paramKey, dictParam[paramKey]);
                            change = true;
                        }
                        else if (!dictParamPre[paramKey].Equals(dictParam[paramKey]))
                        {
                            changeDict["upd"].Add(paramKey, dictParamPre[paramKey] + "=>" + dictParam[paramKey]);
                            change = true;
                        }
                    }

                    foreach (string paramKey in dictParamPre.Keys)
                    {
                        if (!dictParam.ContainsKey(paramKey))
                        {
                            changeDict["del"].Add(paramKey, dictParamPre[paramKey]);
                            change = true;
                        }
                    }
                }
                else
                {
                    change = true;
                }
            }
            catch (Exception e)
            {
                changeText = "判断配置变动异常，" + e.Message;
            }
            finally
            {
                changeText = JsonConvert.SerializeObject(changeDict);
            }

            return change;
        }

        /// <summary>
        /// 通用json遍历
        /// </summary>
        /// <param name="valueDict"></param>
        /// <param name="data"></param>
        /// <param name="prefix"></param>
        /// <param name="gap"></param>
        private Dictionary<string, string> GetDataFromJson(Dictionary<string, string> valueDict, Object data, string prefix = "", string gap = "=>")
        {
            try
            {
                if (data is null)
                {
                    return valueDict;
                }

                if (basicType.ContainsKey(data.GetType().Name))
                {
                    if (!"".Equals(data.ToString()) && !"NULL".Equals(data.ToString()))
                    {
                        valueDict.TryAdd(("".Equals(prefix) ? data.GetType().Name : prefix).ToUpper(), data.ToString());
                    }
                }
                else if (data is Dictionary<string, Object>)
                {
                    Dictionary<string, Object> dataDict = (Dictionary<string, Object>)data;
                    foreach (string key in dataDict.Keys)
                    {
                        Object dataIn = dataDict[key];
                        string name = ("".Equals(prefix) ? "" : prefix + gap) + key;
                        if (dataIn != null)
                        {
                            GetDataFromJson(valueDict, dataIn, name);
                        }
                    }
                }
                else if (data is List<Object>)
                {
                    List<Object> dataList = (List<Object>)data;
                    int i = 0;
                    foreach (var dataIn in dataList)
                    {
                        string name = ("".Equals(prefix) ? "" : prefix + gap) + i;
                        if (dataIn != null)
                        {
                            GetDataFromJson(valueDict, dataIn, name);
                        }
                        i++;
                    }
                }
                else if (data is JObject)
                {
                    Dictionary<string, Object> dataChild = JsonConvert.DeserializeObject<Dictionary<string, Object>>(data.ToString());
                    if (dataChild != null)
                    {
                        GetDataFromJson(valueDict, dataChild, prefix);
                    }
                }
                else if (data is JArray)
                {
                    List<Object> dataChild = JsonConvert.DeserializeObject<List<Object>>(data.ToString());
                    if (dataChild != null)
                    {
                        GetDataFromJson(valueDict, dataChild, prefix);
                    }
                }
                else
                {
                    if (!"".Equals(data.ToString()) && !"NULL".Equals(data.ToString()))
                    {
                        valueDict.TryAdd(("".Equals(prefix) ? data.GetType().Name : prefix).ToUpper(), data.ToString());
                    }
                }
            }
            catch { }

            return valueDict;
        }
        #endregion

        #region http请求相关
        ///// <summary>
        ///// 请求Api资源信息
        ///// Get方式
        ///// </summary>
        ///// <param name="url"></param>
        ///// <returns></returns>
        //public async Task<string> RequestApiResource(string url)
        //{
        //    string result = "";
        //    try
        //    {
        //        //Timeout默认值是 100,000 毫秒（100 秒）。若要设置无限超时，请将属性值设置为 InfiniteTimeSpan
        //        //client.Timeout = TimeSpan.FromMinutes(10);

        //        //每一个api资源都有一个对应的网关地址
        //        HttpResponseMessage response = httpClient.GetAsync(url).Result;
        //        if (response.IsSuccessStatusCode)
        //        {
        //            result = await response.Content.ReadAsStringAsync();
        //        }
        //    }
        //    catch { }
        //    finally
        //    {

        //    }

        //    return result;
        //}

        ///// <summary>
        ///// 请求Api资源信息
        ///// Post方式
        ///// </summary>
        ///// <param name="url"></param>
        ///// <param name="data"></param>
        ///// <returns></returns>
        //public async Task<string> RequestApiResourcePost(string url, string data, string contentType = "application/json")
        //{
        //    string result = "";
        //    try
        //    {
        //        //var content = new StringContent(data, Encoding.UTF8, "application/json");

        //        //在使用编码方法（Encoding.GetEncoding("GB2312")）之前，对编码进行注册
        //        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        //        var content = new StringContent(data, Encoding.GetEncoding(TransForm.encode), contentType);

        //        HttpResponseMessage response = await httpClient.PostAsync(url, content);
        //        if (response.IsSuccessStatusCode)
        //        {
        //            result = await response.Content.ReadAsStringAsync();
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        mLogger.LogError(e.ToString());
        //        result = e.Message;
        //    }
        //    finally
        //    {
        //    }
        //    return result;
        //}
        #endregion

        #region 监控系统WEB API接口
        /// <summary>
        /// 针对websocket的token验证
        /// 预留，暂无用
        /// </summary>
        /// <param name="webApiData"></param>
        /// <returns></returns>
        public bool GetValidToken(IWebApiData webApiData)
        {
            bool rs = true;
            try
            {
                //var authHeader = httpContext.Request.Headers["Authorization"];
                //var token = authHeader.FirstOrDefault()?.Split(" ").Last(); // 假设使用Bearer token
                //rs = !string.IsNullOrEmpty(token);

                //获取token，进行验证
                //string token = webApiData.Data.ToString();
            }
            catch
            {
                rs = false;
            }

            return rs;
        }

        /// <summary>
        /// 接收数据处理
        /// 这里主要是接收下行控制命令，包括自动读取设置和客户端下发的命令
        /// </summary>
        /// <param name="webApiDataFull"></param>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public Object GetDataJson(WebApiDataFull webApiDataFull, HttpContext httpContext)
        {
            var sw = Stopwatch.StartNew();
            bool rs = false;
            try
            {
                string ip = httpContext.Connection.RemoteIpAddress == null ? "" : httpContext.Connection.RemoteIpAddress.ToString().ToUpper().Replace("::FFFF:", "");
                ushort port = (ushort)httpContext.Connection.RemotePort;

                //固定只处理某些命令
                if (webApiDataFull.ContentReq.Command.ToUpper().Equals("some_command"))
                {
                    
                }
                else
                {
                    ((WebApiDataRes)webApiDataFull.ContentRes).Code = WebApiStatusCode.code_404;
                    ((WebApiDataRes)webApiDataFull.ContentRes).Message = EnumHelper.GetDescription(((WebApiDataRes)webApiDataFull.ContentRes).Code) + "，无法响应命令【" + webApiDataFull.ContentReq.Command + "】";
                }
            }
            catch (Exception e)
            {
                ((WebApiDataRes)webApiDataFull.ContentRes).Code = WebApiStatusCode.code_5504;
                ((WebApiDataRes)webApiDataFull.ContentRes).Message = EnumHelper.GetDescription(((WebApiDataRes)webApiDataFull.ContentRes).Code) + "," + e.Message;
            }

            return rs;
        }

        /// <summary>
        /// 参数检查
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public WebParamData CheckParam(HttpContext httpContext)
        {
            WebParamData webParamData = new WebParamData();
            string msg = "";

            try
            {
                //路径参数
                string apiver = (httpContext.Request.RouteValues["apiver"] ?? httpContext.Request.Query["apiver"]).ToString();
                string level = (httpContext.Request.RouteValues["level"] ?? httpContext.Request.Query["level"]).ToString();
                string positionid = (httpContext.Request.RouteValues["positionid"] ?? httpContext.Request.Query["positionid"]).ToString();
                string sn = (httpContext.Request.RouteValues["sn"] ?? httpContext.Request.Query["sn"]).ToString();

                if (apiver == null || "".Equals(apiver))
                {
                    msg += "，API协议版本apiver不能为空";
                }

                if (level == null || "".Equals(level))
                {
                    msg += "，级别level（SYSTEM(系统级) DEVICE(设备级)）不能为空";
                }

                if (positionid == null || "".Equals(positionid))
                {
                    msg += "，位置编号（或工位号）positionid不能为空";
                }

                else if (positionid.Split("_").Length < 3)
                {
                    msg += "，位置编号（或工位号）positionid异常，参考格式xx_xxx_xxx";
                }

                if (sn == null || "".Equals(sn))
                {
                    msg += "，系统/设备序列号sn不能为空";
                }

                webParamData.apiver = apiver;
                webParamData.level = level;
                webParamData.positionid = positionid;
                webParamData.sn = sn;
            }
            catch (Exception e)
            {
                msg += e.Message;
            }
            finally
            {
                webParamData.nowmal = string.IsNullOrEmpty(msg);
                webParamData.msg = webParamData.nowmal ? msg : msg.Substring(1);
            }

            return webParamData;
        }

        /// <summary>
        /// 检查请求参数
        /// </summary>
        /// <param name="data"></param>
        /// <param name="webApiDataRes"></param>
        /// <returns></returns>
        public bool CheckData(string data, WebApiDataFull webApiDataFull)
        {
            bool rs = false;
            string msg = "";
            try
            {
                IWebApiData webApiData = null;
                Dictionary<string, Object> dictData = null;
                if (data != null && !"".Equals(data.ToString()) && ValidJson.IsJson(data.ToString()))
                {
                    dictData = JsonConvert.DeserializeObject<Dictionary<string, Object>>(data.ToString());
                    if (webApiDataFull.IsWebSocket)
                    {
                        webApiData = JsonConvert.DeserializeObject<WebApiDataReqWS>(data.ToString());
                    }
                    else
                    {
                        webApiData = JsonConvert.DeserializeObject<WebApiDataReq>(data.ToString());
                    }

                    if (webApiData == null)
                    {
                        msg += "，数据异常";
                    }
                }
                else
                {
                    msg += "，数据异常";
                }

                //数据必须参数检查
                if (dictData != null && dictData.Count > 0)
                {
                    Dictionary<string, string> tmpDict = dictData.ToDictionary(d => d.Key.ToUpper(), d => "");
                    if (!tmpDict.ContainsKey("REQUESTID"))
                    {
                        msg += "，数据不完整，缺少RequestId（请求编号）参数";
                    }
                    if (!tmpDict.ContainsKey("COMMAND"))
                    {
                        msg += "，数据不完整，缺少Command（命令）参数";
                    }
                    if (!tmpDict.ContainsKey("VERSION"))
                    {
                        msg += "，数据不完整，缺少Version（设备或系统通信协议版本）参数";
                    }
                    if (!tmpDict.ContainsKey("DATA"))
                    {
                        msg += "，数据不完整，缺少Data数据";
                    }
                    if (!tmpDict.ContainsKey("TIMESTAMP"))
                    {
                        msg += "，数据不完整，缺少Timestamp（时间戳）参数";
                    }
                    if (webApiDataFull.IsWebSocket && !tmpDict.ContainsKey("TYPE"))
                    {
                        msg += "，数据不完整，缺少Type（消息类型）参数";
                    }
                }

                webApiDataFull.dictData = dictData;
                webApiDataFull.ContentReq = webApiData;

                //消息类型判断
                if (webApiDataFull.IsWebSocket && webApiData != null && !EnumHelper.HasValue<WebApiTypeCodeWS>(((WebApiDataReqWS)webApiDataFull.ContentReq).Type))
                {
                    msg += "，数据不完整，Type（消息类型）异常";
                }

                //工位号格式处理，确保格式统一
                webApiDataFull.webParamData.positionid = webApiDataFull.webParamData.positionid.Replace("_0X", "_0x");
                rs = string.IsNullOrEmpty(msg);
                if (webApiDataFull.IsWebSocket)
                {
                    ((WebApiDataResWS)webApiDataFull.ContentRes).Code = rs ? WebApiStatusCode.code_200 : WebApiStatusCode.code_400;
                }
                else
                {
                    ((WebApiDataRes)webApiDataFull.ContentRes).Code = rs ? WebApiStatusCode.code_200 : WebApiStatusCode.code_400;
                }
            }
            catch (Exception e)
            {
                rs = false;
                //数据处理从错误
                msg += "，" + e.Message;
                if (webApiDataFull.IsWebSocket)
                {
                    ((WebApiDataResWS)webApiDataFull.ContentRes).Code = WebApiStatusCode.code_5504;
                }
                else
                {
                    ((WebApiDataRes)webApiDataFull.ContentRes).Code = WebApiStatusCode.code_5504;
                }
            }
            finally
            {
                try
                {
                    if (webApiDataFull.IsWebSocket)
                    {
                        ((WebApiDataResWS)webApiDataFull.ContentRes).Message = EnumHelper.GetDescription(((WebApiDataResWS)webApiDataFull.ContentRes).Code) + msg;
                    }
                    else
                    {
                        ((WebApiDataRes)webApiDataFull.ContentRes).Message = EnumHelper.GetDescription(((WebApiDataRes)webApiDataFull.ContentRes).Code) + msg;
                    }

                    if (webApiDataFull.ContentReq != null)
                    {
                        webApiDataFull.ContentRes.RequestId = webApiDataFull.ContentReq.RequestId;
                        webApiDataFull.ContentRes.Command = webApiDataFull.ContentReq.Command;
                        webApiDataFull.ContentRes.Version = webApiDataFull.ContentReq.Version;
                        if (webApiDataFull.IsWebSocket)
                        {
                            if (rs)
                            {
                                ((WebApiDataResWS)webApiDataFull.ContentRes).Type = ((WebApiDataReqWS)webApiDataFull.ContentReq).Type.ToLower();
                            }
                            else
                            {
                                ((WebApiDataResWS)webApiDataFull.ContentRes).Type = WebApiTypeCodeWS.error.ToString();
                            }
                        }
                    }
                }
                catch
                {
                    rs = false;
                    //服务异常失败
                    if (webApiDataFull.IsWebSocket)
                    {
                        ((WebApiDataResWS)webApiDataFull.ContentRes).Code = WebApiStatusCode.code_5503;
                        ((WebApiDataResWS)webApiDataFull.ContentRes).Message = EnumHelper.GetDescription(((WebApiDataResWS)webApiDataFull.ContentRes).Code);
                    }
                    else
                    {
                        ((WebApiDataRes)webApiDataFull.ContentRes).Code = WebApiStatusCode.code_5503;
                        ((WebApiDataRes)webApiDataFull.ContentRes).Message = EnumHelper.GetDescription(((WebApiDataRes)webApiDataFull.ContentRes).Code);
                    }
                }
            }

            return rs;
        }
        #endregion

        /// <summary>
        /// 通用状态返回
        /// </summary>
        /// <returns></returns>
        public CommonDataRes GetStatus()
        { 
            CommonDataRes commonDataRes = new CommonDataRes();

            Dictionary<string, Object> status = new();
            status.TryAdd("wsCount", WebsocketClientManager.websocketClient.GetCount());
            commonDataRes.Data = status;

            return commonDataRes;
        }

        /// <summary>
        /// 获取客户端IP
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public string GetClientIp(HttpContext httpContext)
        {
            string ip = "";
            try
            {
                int agentType = GetAgentType(httpContext);
                //web版本访问时，由于科江使用了代理，特定传输了这两个参数
                if (agentType == 2)
                {
                    ip = httpContext.Request.Headers["X-Real-IP"].ToString();
                    if (string.IsNullOrEmpty(ip))
                    {
                        httpContext.Request.Headers["X-Forwarded-For"].ToString();
                    }
                    if (string.IsNullOrEmpty(ip))
                    {
                        ip = httpContext.Connection.RemoteIpAddress == null ? "" : httpContext.Connection.RemoteIpAddress.ToString().ToUpper().Replace("F", "").Replace(":", "");
                    }
                }
                else
                {
                    ip = httpContext.Connection.RemoteIpAddress == null ? "" : httpContext.Connection.RemoteIpAddress.ToString().ToUpper().Replace("F", "").Replace(":", "");
                }
            }
            catch (Exception e)
            { }

            return ip;
        }

        /// <summary>
        /// 获取客户端类型
        /// 0-是测试的Apifox或者Postman
        /// 1-是cs客户端（即User-Agent为空串）
        /// 2-是bs客户端
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public int GetAgentType(HttpContext httpContext)
        {
            int agentType = 0;
            try
            {
                string agent = httpContext.Request.Headers["User-Agent"].ToString();

                //是否cs客户端，用以区分是否cs客户端，因为web客户端的布局和cs客户端的不一样，需要区别开来
                //cs客户端过来的agent为空串
                //POSTMAN和APIFOX是测试
                //CSCLIENT是和客户端约定的字符串
                //agentType = (agent.ToUpper().Contains("POSTMAN") || agent.ToUpper().Contains("APIFOX")) ? 0 : ("CSCLIENT".Equals(agent.ToUpper()) ? 1 : 2);
                agentType = (agent.ToUpper().Contains("POSTMAN") || agent.ToUpper().Contains("APIFOX")) ? 0 : ("".Equals(agent.ToUpper()) ? 1 : 2);
            }
            catch (Exception e)
            { }

            return agentType;
        }

        #region 日志打印
        /// <summary>
        /// 定时打印提示信息
        /// 定时重新初始化
        /// </summary>
        private void TimerTask()
        {
            int times = 0;
            Thread.Sleep(10 * 1000);
            while (true)
            {
                mLogger.LogInformation(nodeName +
                    " 线程数=" + ThreadPool.ThreadCount +
                    " WS连接=" + WebsocketClientManager.websocketClient.GetCount()
                    );

                times++;
                if (times > 10000 * 1000)
                {
                    times = 1;
                }
                Thread.Sleep(10 * 1000);
            }
        }
        #endregion
    }
}
